/**
 * ======================================================
 * virtuals.cpp
 *
 * Valve virtual function declarations
 * ======================================================
 *
 * The MIT License
 * 
 * Copyright (c) 2008 Matthew Maravillas
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Version: $Id$
 */

#include "virtuals.h"

class EmptyClass {};

#ifdef __linux__
#define VFUNC_OS_DEP void *addr;	} u; 	u.addr = func;
#else
#define VFUNC_OS_DEP struct {void *addr; intptr_t adjustor;} s; } u; u.s.addr = func; u.s.adjustor = 0;
#endif

#define VFUNC_SETUP_PTR(_vfunc_offset)  \
{ \
	void **this_ptr = *(void ***)&pThisPtr; \
	void **vtable = *(void ***)pThisPtr; \
    void *func = vtable[_vfunc_offset]

// Macros for defining functions to call vfuncs via offset.

#define VFUNC_CALL0(_vfunc_offset, _return_type, _class_type, _func_name ) \
	_return_type _func_name(_class_type *pThisPtr) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { _return_type (EmptyClass::*mfpnew)(); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)();} 

#define VFUNC_CALL1(_vfunc_offset, _return_type, _class_type, _func_name, _param1) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { _return_type (EmptyClass::*mfpnew)(_param1); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1);} 

#define VFUNC_CALL2(_vfunc_offset, _return_type, _class_type, _func_name, _param1, _param2) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { _return_type (EmptyClass::*mfpnew)(_param1, _param2); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2);} 

#define VFUNC_CALL3(_vfunc_offset, _return_type, _class_type, _func_name, _param1, _param2, _param3) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { _return_type (EmptyClass::*mfpnew)(_param1, _param2, _param3); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3);} 

#define VFUNC_CALL4(_vfunc_offset, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { _return_type (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4);} 

#define VFUNC_CALL5(_vfunc_offset, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { _return_type (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5);} 

#define VFUNC_CALL6(_vfunc_offset, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { _return_type (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6);} 

#define VFUNC_CALL7(_vfunc_offset, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { _return_type (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7);} 

#define VFUNC_CALL8(_vfunc_offset, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7, _param8 p8) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { _return_type (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7, p8);} 

#define VFUNC_CALL9(_vfunc_offset, _return_type, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8, _param9) \
	_return_type _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7, _param8 p8, _param9) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { _return_type (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8, _param9); \
	VFUNC_OS_DEP \
 	return (_return_type) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7, p8, p9);} 

#define VFUNC_CALL0_void(_vfunc_offset, _class_type, _func_name ) \
	void _func_name(_class_type *pThisPtr) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { void (EmptyClass::*mfpnew)(); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)();} 

#define VFUNC_CALL1_void(_vfunc_offset, _class_type, _func_name, _param1) \
	void _func_name(_class_type *pThisPtr, _param1 p1) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { void (EmptyClass::*mfpnew)(_param1); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1);} 

#define VFUNC_CALL2_void(_vfunc_offset, _class_type, _func_name, _param1, _param2) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { void (EmptyClass::*mfpnew)(_param1, _param2); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2);} 

#define VFUNC_CALL3_void(_vfunc_offset, _class_type, _func_name, _param1, _param2, _param3) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { void (EmptyClass::*mfpnew)(_param1, _param2, _param3); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3);} 

#define VFUNC_CALL4_void(_vfunc_offset, _class_type, _func_name, _param1, _param2, _param3, _param4) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { void (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4);} 

#define VFUNC_CALL5_void(_vfunc_offset, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { void (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5);} 

#define VFUNC_CALL6_void(_vfunc_offset, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { void (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6);} 

#define VFUNC_CALL7_void(_vfunc_offset, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { void (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7);} 

#define VFUNC_CALL8_void(_vfunc_offset, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7, _param8 p8) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { void (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7, p8);} 

#define VFUNC_CALL9_void(_vfunc_offset, _class_type, _func_name, _param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8, _param9) \
	void _func_name(_class_type *pThisPtr, _param1 p1, _param2 p2, _param3 p3, _param4 p4, _param5 p5, _param6 p6, _param7 p7, _param8 p8, _param9) \
	VFUNC_SETUP_PTR(_vfunc_offset); \
	union { void (EmptyClass::*mfpnew)(_param1, _param2, _param3, _param4, _param5, _param6, _param7, _param8, _param9); \
	VFUNC_OS_DEP \
 	(void) (reinterpret_cast<EmptyClass*>(this_ptr)->*u.mfpnew)(p1, p2, p3, p4, p5, p6, p7, p8, p9);} 

// virtual CBaseCombatWeapon *Weapon_GetSlot( int slot ) const;
